package com.fulu.game.bi.service.impl.roi;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.fulu.game.bi.common.exception.BizException;
import com.fulu.game.bi.common.util.csv.CsvExportUtil;
import com.fulu.game.bi.common.util.csv.Mapper;
import com.fulu.game.bi.common.util.csv.Querier;
import com.fulu.game.bi.common.util.lang.StringUtils;
import com.fulu.game.bi.entity.enums.QueryTypeStatusEnum;
import com.fulu.game.bi.entity.po.channel.Label;
import com.fulu.game.bi.entity.po.channel.RegistSource;
import com.fulu.game.bi.entity.po.roi.Delivery;
import com.fulu.game.bi.entity.po.roi.NewAddUserStat;
import com.fulu.game.bi.entity.po.roi.RoiStat;
import com.fulu.game.bi.entity.vo.roi.RoiStatDisplayVO;
import com.fulu.game.bi.entity.vo.roi.RoiStatQueryVO;
import com.fulu.game.bi.mysql.bi.channel.LabelGroupDao;
import com.fulu.game.bi.mysql.bi.channel.RegisterSourceGroupDao;
import com.fulu.game.bi.mysql.bi.roi.DeliveryCostDao;
import com.fulu.game.bi.mysql.bi.roi.RoiStatDao;
import com.fulu.game.bi.mysql.playadmin.channel.LabelDao;
import com.fulu.game.bi.mysql.playadmin.channel.RegistSourceDao;
import com.fulu.game.bi.redis.service.roi.RoiStatService;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Slf4j
public class RoiStatServiceImpl implements RoiStatService {

    private static final String PLACEHOLDER = "/";

    @Autowired
    private RoiStatDao roiStatDao;

    @Autowired
    private RegisterSourceGroupDao registerSourceGroupDao;

    @Autowired
    private LabelGroupDao labelGroupDao;

    @Autowired
    private LabelDao labelDao;

    @Autowired
    private DeliveryCostDao deliveryCostDao;

    @Autowired
    private RegistSourceDao registSourceDao;

    public static final Map<Integer, String> tableNameMap = new HashMap();

    static {
        tableNameMap.put(QueryTypeStatusEnum.DAY.getType(), "t_roi_stat_day");
        tableNameMap.put(QueryTypeStatusEnum.WEEK.getType(), "t_roi_stat_week");
        tableNameMap.put(QueryTypeStatusEnum.MONTH.getType(), "t_roi_stat_month");
    }

    @Override
    public List<RoiStatDisplayVO> list(RoiStatQueryVO vo) {
        boolean noUniqSourceId = CollectionUtil.isEmpty(vo.getRegisterSourceIdList());
        boolean noUniqLabelId = CollectionUtil.isEmpty(vo.getLabelIdList());

        // 装配渠道
        String registerSourceGroupName = PLACEHOLDER;
        if (Objects.nonNull(vo.getRegisterSourceGroupId()) && CollectionUtil.isEmpty(vo.getRegisterSourceIdList())) {
            List<Integer> sourceIdList = registerSourceGroupDao.listItem(vo.getRegisterSourceGroupId());
            if (CollectionUtil.isEmpty(sourceIdList)) {
                return new ArrayList<>();
            }
            registerSourceGroupName = registerSourceGroupDao.findNameById(vo.getRegisterSourceGroupId());

            vo.setRegisterSourceIdList(sourceIdList);
        }

        Map<Integer, String> sourceMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(vo.getRegisterSourceIdList())) {
            List<RegistSource> sourceList = registSourceDao.findByIds(vo.getRegisterSourceIdList()).stream()
                    .collect(Collectors.toList());
            List<Integer> platforms = sourceList.stream().map(RegistSource::getPlatform).collect(Collectors.toList());
            vo.setRegisterSourceIdList(platforms);

            sourceMap = sourceList.stream().collect(Collectors.toMap(RegistSource::getPlatform, RegistSource::getName));
        }

        // 装配标签
        String labelGroupName = PLACEHOLDER;
        if (Objects.nonNull(vo.getLabelGroupId()) && CollectionUtil.isEmpty(vo.getLabelIdList())) {
            List<Integer> labelIdList = labelGroupDao.listItem(vo.getLabelGroupId());
            if (CollectionUtil.isEmpty(labelIdList)) {
                return new ArrayList<>();
            }
            labelGroupName = labelGroupDao.findNameById(vo.getLabelGroupId());

            vo.setLabelIdList(labelIdList);

        }

        Map<Integer, String> labelMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(vo.getLabelIdList())) {
            labelMap = labelDao.findByIds(vo.getLabelIdList()).stream().collect(Collectors.toMap(Label::getId, Label::getName));
        }

        String tableName = tableNameMap.get(vo.getQueryType());
        Optional.ofNullable(tableName).orElseThrow(() -> new BizException("不支持的查询类型"));

        List<RoiStat> list = roiStatDao.list(vo, tableName);

        String finalRegisterSourceGroupName = registerSourceGroupName;
        String finalLabelGroupName = labelGroupName;
        log.info("查询结果list ：{}", list);
        Map<Integer, String> finalLabelMap = labelMap;
        Map<Integer, String> finalSourceMap = sourceMap;
        List<RoiStatDisplayVO> result = list.stream()
                .map(roiStat -> {
                    RoiStatDisplayVO displayVO = new RoiStatDisplayVO();
                    BeanUtils.copyProperties(roiStat, displayVO);
                    return displayVO;
                })
                .peek(v -> v.setRegisterSourceGroupName(finalRegisterSourceGroupName))
                .peek(v -> v.setLabelGroupName(finalLabelGroupName))
                .peek(v -> setEndDateStr(vo, v))
                .peek(v -> v.setBeginStatDay(v.getStatDate()))
                .peek(v -> {
                    if (CollectionUtil.isEmpty(vo.getLabelIdList())) {
                        v.setLabelName(PLACEHOLDER);
                    } else {
                        v.setLabelName(finalLabelMap.get(v.getLabelId()));
                    }
                })
                .peek(v -> {
                    if (CollectionUtil.isEmpty(vo.getRegisterSourceIdList())) {
                        v.setRegisterSourceName(PLACEHOLDER);
                    } else {
                        v.setRegisterSourceName(finalSourceMap.get(v.getSourceId()));
                    }
                })
                .peek(v -> computeDelivery(v, vo))
                .peek(v -> v.setSourceId(v.getSourceId() == null ? 0 : v.getSourceId()))
                .sorted(Comparator.comparing(RoiStatDisplayVO::getStatDate).reversed().thenComparing(RoiStatDisplayVO::getSourceId))
                .collect(Collectors.toList());

        if (StringUtils.isNotEmpty(vo.getRegisterSourceGroupId()) && noUniqSourceId) {
            return completeGroupCost(vo, result);
        }
        if (StringUtils.isNotEmpty(vo.getLabelGroupId()) && noUniqLabelId) {
            return completeLabelGroupCost(vo, result);
        }


        return result;
    }

    private void setEndDateStr(RoiStatQueryVO vo, RoiStatDisplayVO v) {
        if (QueryTypeStatusEnum.WEEK.getType().equals(vo.getQueryType())) {
            DateTime startTime = DateUtil.parse(v.getStatDate());
            DateTime endDateTime = DateUtil.offsetDay(startTime, 6);

            String statDateEnd = DateUtil.format(endDateTime, "yyyy-MM-dd");
            v.setEndStatDay(statDateEnd);
        } else {
            v.setEndStatDay(v.getStatDate());
        }
    }

    protected List<RoiStatDisplayVO> completeLabelGroupCost(RoiStatQueryVO vo, List<RoiStatDisplayVO> result) {
        List<RoiStatDisplayVO> list = new ArrayList<>();

        Map<String, List<RoiStatDisplayVO>> map = result.stream().collect(Collectors.groupingBy(v -> v.getStatDate() + "/" + v.getLabelGroupName()));

        map.forEach((key, value) -> {
            int payUser = value.stream().map(RoiStatDisplayVO::getPayUserNum).filter(Objects::nonNull).mapToInt(Integer::intValue).sum();
            int newUser = value.stream().map(RoiStatDisplayVO::getNewUserNum).filter(Objects::nonNull).mapToInt(Integer::intValue).sum();

            RoiStatQueryVO queryVO = new RoiStatQueryVO();
            queryVO.setLabelGroupId(vo.getLabelGroupId());

            String statDate = key.split("/")[0];

            // 非日的不用查询
            if (!QueryTypeStatusEnum.getEnum(vo.getQueryType()).equals(QueryTypeStatusEnum.DAY)) {
                reduce(list, value, statDate, null, null, null);
                return;
            }
            DateTime dateTimeBegin = DateUtil.beginOfDay(DateUtil.parseDate(statDate));
            DateTime dateTimeEnd = DateUtil.endOfDay(DateUtil.parseDate(statDate));

            queryVO.setValidTimeEnd(dateTimeEnd);
            queryVO.setValidTimeStart(dateTimeBegin);
            List<Delivery> deliveryList = deliveryCostDao.list(queryVO);
            if (CollectionUtil.isEmpty(deliveryList)) {
                reduce(list, value, statDate, null, null, null);
                return;
            }

            Delivery delivery = deliveryList.get(0);
            // 投放成本
            BigDecimal deliveryCost = delivery.getDeliveryCost();
            BigDecimal registrationCost = BigDecimal.ZERO;
            if (newUser > 0) {
                registrationCost = deliveryCost.divide(new BigDecimal(newUser), 2, BigDecimal.ROUND_HALF_UP);
            }
            BigDecimal paidCost = BigDecimal.ZERO;
            if (payUser > 0) {
                paidCost = deliveryCost.divide(new BigDecimal(payUser), 2, BigDecimal.ROUND_HALF_UP);
            }

            BigDecimal finalRegistrationCost = registrationCost;
            BigDecimal finalPaidCost = paidCost;

            reduce(list, value, statDate, deliveryCost, finalRegistrationCost, finalPaidCost);
        });

        list.sort(Comparator.comparing(RoiStatDisplayVO::getStatDate).reversed());
        return list;
    }

    private void reduce(List<RoiStatDisplayVO> list, List<RoiStatDisplayVO> value, String statDate, BigDecimal deliveryCost, BigDecimal finalRegistrationCost, BigDecimal finalPaidCost) {
        RoiStatDisplayVO displayVO = value.get(0);
        RoiStatDisplayVO temp = Optional.ofNullable(displayVO).orElse(displayVO);
        RoiStatDisplayVO total = new RoiStatDisplayVO();
        total.setDeliveryCost(deliveryCost);
        // 注册成本
        total.setRegistrationCost(BigDecimal.ZERO);
        total.setRegistrationCost(finalRegistrationCost);
        // 付费成本
        total.setPaidCost(finalPaidCost);
        total.setStatDate(statDate);
        total.setRegisterSourceGroupName(temp.getRegisterSourceGroupName());
        total.setRegisterSourceName("/");
        total.setLabelGroupName(temp.getLabelGroupName());
        total.setLabelId(temp.getLabelId());
        total.setLabelName("/");
        total.setRegisterType(temp.getRegisterType());
        total.setNewUserNum(value.stream().map(RoiStatDisplayVO::getNewUserNum).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setActiveUserNum(value.stream().map(RoiStatDisplayVO::getActiveUserNum).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setPayUserNum(value.stream().map(RoiStatDisplayVO::getPayUserNum).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllMoney1(value.stream().map(RoiStatDisplayVO::getAllMoney1).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney2(value.stream().map(RoiStatDisplayVO::getAllMoney2).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney3(value.stream().map(RoiStatDisplayVO::getAllMoney3).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney4(value.stream().map(RoiStatDisplayVO::getAllMoney4).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney5(value.stream().map(RoiStatDisplayVO::getAllMoney5).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney6(value.stream().map(RoiStatDisplayVO::getAllMoney6).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney7(value.stream().map(RoiStatDisplayVO::getAllMoney7).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney8(value.stream().map(RoiStatDisplayVO::getAllMoney8).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney9(value.stream().map(RoiStatDisplayVO::getAllMoney9).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney10(value.stream().map(RoiStatDisplayVO::getAllMoney10).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney11(value.stream().map(RoiStatDisplayVO::getAllMoney11).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney12(value.stream().map(RoiStatDisplayVO::getAllMoney12).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney13(value.stream().map(RoiStatDisplayVO::getAllMoney13).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney14(value.stream().map(RoiStatDisplayVO::getAllMoney14).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney15(value.stream().map(RoiStatDisplayVO::getAllMoney15).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney16(value.stream().map(RoiStatDisplayVO::getAllMoney16).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney17(value.stream().map(RoiStatDisplayVO::getAllMoney17).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney18(value.stream().map(RoiStatDisplayVO::getAllMoney18).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney19(value.stream().map(RoiStatDisplayVO::getAllMoney19).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney20(value.stream().map(RoiStatDisplayVO::getAllMoney20).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney21(value.stream().map(RoiStatDisplayVO::getAllMoney21).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney22(value.stream().map(RoiStatDisplayVO::getAllMoney22).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney23(value.stream().map(RoiStatDisplayVO::getAllMoney23).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney24(value.stream().map(RoiStatDisplayVO::getAllMoney24).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney25(value.stream().map(RoiStatDisplayVO::getAllMoney25).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney26(value.stream().map(RoiStatDisplayVO::getAllMoney26).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney27(value.stream().map(RoiStatDisplayVO::getAllMoney27).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney28(value.stream().map(RoiStatDisplayVO::getAllMoney28).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney29(value.stream().map(RoiStatDisplayVO::getAllMoney29).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllMoney30(value.stream().map(RoiStatDisplayVO::getAllMoney30).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        total.setAllNum1(value.stream().map(RoiStatDisplayVO::getAllNum1).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum2(value.stream().map(RoiStatDisplayVO::getAllNum2).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum3(value.stream().map(RoiStatDisplayVO::getAllNum3).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum4(value.stream().map(RoiStatDisplayVO::getAllNum4).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum5(value.stream().map(RoiStatDisplayVO::getAllNum5).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum6(value.stream().map(RoiStatDisplayVO::getAllNum6).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum7(value.stream().map(RoiStatDisplayVO::getAllNum7).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum8(value.stream().map(RoiStatDisplayVO::getAllNum8).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum9(value.stream().map(RoiStatDisplayVO::getAllNum9).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum10(value.stream().map(RoiStatDisplayVO::getAllNum10).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum11(value.stream().map(RoiStatDisplayVO::getAllNum11).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum12(value.stream().map(RoiStatDisplayVO::getAllNum12).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum13(value.stream().map(RoiStatDisplayVO::getAllNum13).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum14(value.stream().map(RoiStatDisplayVO::getAllNum14).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum15(value.stream().map(RoiStatDisplayVO::getAllNum15).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum16(value.stream().map(RoiStatDisplayVO::getAllNum16).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum17(value.stream().map(RoiStatDisplayVO::getAllNum17).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum18(value.stream().map(RoiStatDisplayVO::getAllNum18).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum19(value.stream().map(RoiStatDisplayVO::getAllNum19).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum20(value.stream().map(RoiStatDisplayVO::getAllNum20).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum21(value.stream().map(RoiStatDisplayVO::getAllNum21).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum22(value.stream().map(RoiStatDisplayVO::getAllNum22).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum23(value.stream().map(RoiStatDisplayVO::getAllNum23).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum24(value.stream().map(RoiStatDisplayVO::getAllNum24).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum25(value.stream().map(RoiStatDisplayVO::getAllNum25).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum26(value.stream().map(RoiStatDisplayVO::getAllNum26).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum27(value.stream().map(RoiStatDisplayVO::getAllNum27).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum28(value.stream().map(RoiStatDisplayVO::getAllNum28).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum29(value.stream().map(RoiStatDisplayVO::getAllNum29).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
        total.setAllNum30(value.stream().map(RoiStatDisplayVO::getAllNum30).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());

        list.add(total);
    }

    protected List<RoiStatDisplayVO> completeGroupCost(RoiStatQueryVO vo, List<RoiStatDisplayVO> result) {
        List<RoiStatDisplayVO> list = new ArrayList<>();
        Map<String, List<RoiStatDisplayVO>> map = result.stream().collect(Collectors.groupingBy(v -> v.getStatDate() + "/" + v.getRegisterSourceGroupName()));
        map.forEach((key, value) -> {
            int payUser = value.stream().map(RoiStatDisplayVO::getPayUserNum).filter(Objects::nonNull).mapToInt(Integer::intValue).sum();
            int newUser = value.stream().map(RoiStatDisplayVO::getNewUserNum).filter(Objects::nonNull).mapToInt(Integer::intValue).sum();

            RoiStatQueryVO queryVO = new RoiStatQueryVO();
            queryVO.setRegisterSourceGroupId(vo.getRegisterSourceGroupId());

            String statDate = key.split("/")[0];
            // 非日的不用查询
            if (!QueryTypeStatusEnum.getEnum(vo.getQueryType()).equals(QueryTypeStatusEnum.DAY)) {
                reduce(list, value, statDate, null, null, null);
                return;
            }
            DateTime dateTimeBegin = DateUtil.beginOfDay(DateUtil.parseDate(statDate));
            DateTime dateTimeEnd = DateUtil.endOfDay(DateUtil.parseDate(statDate));

            queryVO.setValidTimeEnd(dateTimeEnd);
            queryVO.setValidTimeStart(dateTimeBegin);
            List<Delivery> deliveryList = deliveryCostDao.list(queryVO);
            if (CollectionUtil.isEmpty(deliveryList)) {
                reduce(list, value, statDate, null, null, null);
                return;
            }

            Delivery delivery = deliveryList.get(0);
            // 投放成本
            BigDecimal deliveryCost = delivery.getDeliveryCost();
            BigDecimal registrationCost = BigDecimal.ZERO;
            if (newUser > 0) {
                registrationCost = deliveryCost.divide(new BigDecimal(newUser), 2, BigDecimal.ROUND_HALF_UP);
            }
            BigDecimal paidCost = BigDecimal.ZERO;
            if (payUser > 0) {
                paidCost = deliveryCost.divide(new BigDecimal(payUser), 2, BigDecimal.ROUND_HALF_UP);
            }

            BigDecimal finalRegistrationCost = registrationCost;
            BigDecimal finalPaidCost = paidCost;

            reduce(list, value, statDate, deliveryCost, finalRegistrationCost, finalPaidCost);
        });
        list.sort(Comparator.comparing(RoiStatDisplayVO::getStatDate).reversed());
        return list;
    }

    protected void computeDelivery(RoiStatDisplayVO v, RoiStatQueryVO vo) {
        // 非日的不用查询
        if (!QueryTypeStatusEnum.getEnum(vo.getQueryType()).equals(QueryTypeStatusEnum.DAY)) {
            return;
        }
        // 这里和产品沟通过，如果同时使用多个条件查询，则不用进行赋值
        RoiStatQueryVO queryVO = new RoiStatQueryVO();
        queryVO.setRegisterSourceGroupId(vo.getRegisterSourceGroupId());
        List<Integer> registerSourceIdList = vo.getRegisterSourceIdList();
        if (CollectionUtil.isNotEmpty(registerSourceIdList)) {
            List<RegistSource> platforms = registSourceDao.findByPlatforms(registerSourceIdList.toArray(new Integer[0]));
            List<Integer> idList = platforms.stream().map(RegistSource::getId).collect(Collectors.toList());
            queryVO.setRegisterSourceIdList(idList);
        }
        queryVO.setLabelGroupId(vo.getLabelGroupId());
        queryVO.setLabelIdList(vo.getLabelIdList());

        Integer payNum = 0;
        if (vo.getQueryType() < QueryTypeStatusEnum.WEEK.getType()) {
            payNum = v.getAllNum30();
        } else {
            payNum = v.getAllNum12();
        }
        v.setPayUserNum(payNum);

        Map<String, Object> beanMap = BeanUtil.beanToMap(queryVO, false, true);
        if (beanMap.size() != 1) {
            return;
        }

        String statDate = v.getStatDate();
        DateTime dateTimeBegin = DateUtil.beginOfDay(DateUtil.parseDate(statDate));
        DateTime dateTimeEnd = DateUtil.endOfDay(DateUtil.parseDate(statDate));

        queryVO.setValidTimeEnd(dateTimeEnd);
        queryVO.setValidTimeStart(dateTimeBegin);
        List<Delivery> list = deliveryCostDao.list(queryVO);
        if (CollectionUtil.isEmpty(list)) {
            return;
        }

        Delivery delivery = list.get(0);
        // 投放成本
        BigDecimal deliveryCost = delivery.getDeliveryCost();
        v.setDeliveryCost(deliveryCost);

        // 注册成本
        v.setRegistrationCost(BigDecimal.ZERO);
        if (v.getNewUserNum() > 0) {
            v.setRegistrationCost(deliveryCost.divide(new BigDecimal(v.getNewUserNum()), 2, BigDecimal.ROUND_HALF_UP));
        }

        // 付费成本
        v.setPaidCost(BigDecimal.ZERO);
        if (payNum > 0) {
            v.setPaidCost(deliveryCost.divide(new BigDecimal(payNum), 2, BigDecimal.ROUND_HALF_UP));
        }
    }

    @Override
    public void export(RoiStatQueryVO vo) {
        QueryTypeStatusEnum anEnum = QueryTypeStatusEnum.getEnum(vo.getQueryType());
        String site = anEnum.getMsg();

        String fileName = "新增用户" + vo.getStatTimeStart() + "-" + vo.getStatTimeEnd();

        LinkedHashMap<String, Mapper<RoiStatDisplayVO>> map = new LinkedHashMap<>();

        map.put("统计时间", v -> v.getBeginStatDay() + "-" + v.getEndStatDay());
        map.put("渠道来源名称", v -> v.getRegisterSourceName());
        map.put("标签分组名称", v -> v.getLabelGroupName());
//        map.put("标签id", v -> v.getLabelId() + "");
        map.put("标签名称", v -> v.getLabelName() + "");
//        map.put("注册类型系统", v -> v.getRegisterType() + "");
        map.put("新用户数", v -> v.getNewUserNum() + "");
        map.put("激活用户数", v -> v.getActiveUserNum() + "");
        map.put("付费用户数", v -> v.getPayUserNum() + "");
        map.put("投放费用", v -> v.getDeliveryCost() + "");
        map.put("注册成本", v -> v.getRegistrationCost() + "");
        map.put("付费成本", v -> v.getPaidCost() + "");

        switch (anEnum) {
            case DAY:
                map.put("1" + site + "内总充值金额", v -> v.getAllMoney1() + "");
                map.put("2" + site + "内总充值金额", v -> v.getAllMoney2() + "");
                map.put("3" + site + "内总充值金额", v -> v.getAllMoney3() + "");
                map.put("4" + site + "内总充值金额", v -> v.getAllMoney4() + "");
                map.put("5" + site + "内总充值金额", v -> v.getAllMoney5() + "");
                map.put("6" + site + "内总充值金额", v -> v.getAllMoney6() + "");
                map.put("7" + site + "内总充值金额", v -> v.getAllMoney7() + "");
                map.put("14" + site + "内总充值金额", v -> v.getAllMoney14() + "");
                map.put("30" + site + "内总充值金额", v -> v.getAllMoney30() + "");

                map.put("1" + site + "内总充值人数", v -> v.getAllNum1() + "");
                map.put("2" + site + "内总充值人数", v -> v.getAllNum2() + "");
                map.put("3" + site + "内总充值人数", v -> v.getAllNum3() + "");
                map.put("4" + site + "内总充值人数", v -> v.getAllNum4() + "");
                map.put("5" + site + "内总充值人数", v -> v.getAllNum5() + "");
                map.put("6" + site + "内总充值人数", v -> v.getAllNum6() + "");
                map.put("7" + site + "内总充值人数", v -> v.getAllNum7() + "");
                map.put("14" + site + "内总充值人数", v -> v.getAllNum14() + "");
                map.put("30" + site + "内总充值人数", v -> v.getAllNum30() + "");

                map.put("1" + site + "内ROI", v -> ratio(v.getAllMoney1(), v.getDeliveryCost()) + "");
                map.put("2" + site + "内ROI", v -> ratio(v.getAllMoney2(), v.getDeliveryCost()) + "");
                map.put("3" + site + "内ROI", v -> ratio(v.getAllMoney3(), v.getDeliveryCost()) + "");
                map.put("4" + site + "内ROI", v -> ratio(v.getAllMoney4(), v.getDeliveryCost()) + "");
                map.put("5" + site + "内ROI", v -> ratio(v.getAllMoney5(), v.getDeliveryCost()) + "");
                map.put("6" + site + "内ROI", v -> ratio(v.getAllMoney6(), v.getDeliveryCost()) + "");
                map.put("7" + site + "内ROI", v -> ratio(v.getAllMoney7(), v.getDeliveryCost()) + "");
                map.put("14" + site + "内ROI", v -> ratio(v.getAllMoney14(), v.getDeliveryCost()) + "");
                map.put("30" + site + "内ROI", v -> ratio(v.getAllMoney30(), v.getDeliveryCost()) + "");

                break;
            default:
                map.put("1" + site + "内总充值金额", v -> v.getAllMoney1() + "");
                map.put("2" + site + "内总充值金额", v -> v.getAllMoney2() + "");
                map.put("3" + site + "内总充值金额", v -> v.getAllMoney3() + "");
                map.put("4" + site + "内总充值金额", v -> v.getAllMoney4() + "");
                map.put("5" + site + "内总充值金额", v -> v.getAllMoney5() + "");
                map.put("6" + site + "内总充值金额", v -> v.getAllMoney6() + "");
                map.put("7" + site + "内总充值金额", v -> v.getAllMoney7() + "");
                map.put("8" + site + "内总充值金额", v -> v.getAllMoney8() + "");
                map.put("9" + site + "内总充值金额", v -> v.getAllMoney9() + "");
                map.put("10" + site + "内总充值金额", v -> v.getAllMoney10() + "");
                map.put("11" + site + "内总充值金额", v -> v.getAllMoney11() + "");
                map.put("12" + site + "内总充值金额", v -> v.getAllMoney12() + "");

                map.put("1" + site + "内总充值人数", v -> v.getAllNum1() + "");
                map.put("2" + site + "内总充值人数", v -> v.getAllNum2() + "");
                map.put("3" + site + "内总充值人数", v -> v.getAllNum3() + "");
                map.put("4" + site + "内总充值人数", v -> v.getAllNum4() + "");
                map.put("5" + site + "内总充值人数", v -> v.getAllNum5() + "");
                map.put("6" + site + "内总充值人数", v -> v.getAllNum6() + "");
                map.put("7" + site + "内总充值人数", v -> v.getAllNum7() + "");
                map.put("8" + site + "内总充值人数", v -> v.getAllNum8() + "");
                map.put("9" + site + "内总充值人数", v -> v.getAllNum9() + "");
                map.put("10" + site + "内总充值人数", v -> v.getAllNum10() + "");
                map.put("11" + site + "内总充值人数", v -> v.getAllNum11() + "");
                map.put("12" + site + "内总充值人数", v -> v.getAllNum12() + "");

                map.put("1" + site + "内ROI", v -> ratio(v.getAllMoney1(), v.getDeliveryCost()) + "");
                map.put("2" + site + "内ROI", v -> ratio(v.getAllMoney2(), v.getDeliveryCost()) + "");
                map.put("3" + site + "内ROI", v -> ratio(v.getAllMoney3(), v.getDeliveryCost()) + "");
                map.put("4" + site + "内ROI", v -> ratio(v.getAllMoney4(), v.getDeliveryCost()) + "");
                map.put("5" + site + "内ROI", v -> ratio(v.getAllMoney5(), v.getDeliveryCost()) + "");
                map.put("6" + site + "内ROI", v -> ratio(v.getAllMoney6(), v.getDeliveryCost()) + "");
                map.put("7" + site + "内ROI", v -> ratio(v.getAllMoney7(), v.getDeliveryCost()) + "");
                map.put("8" + site + "内ROI", v -> ratio(v.getAllMoney8(), v.getDeliveryCost()) + "");
                map.put("9" + site + "内ROI", v -> ratio(v.getAllMoney9(), v.getDeliveryCost()) + "");
                map.put("10" + site + "内ROI", v -> ratio(v.getAllMoney10(), v.getDeliveryCost()) + "");
                map.put("11" + site + "内ROI", v -> ratio(v.getAllMoney11(), v.getDeliveryCost()) + "");
                map.put("12" + site + "内ROI", v -> ratio(v.getAllMoney12(), v.getDeliveryCost()) + "");
                break;
        }

        Querier querier = (num) -> {
            List<RoiStatDisplayVO> list = list(vo);
            PageInfo<NewAddUserStat> page = new PageInfo(list);
            page.setHasNextPage(false);
            return page;
        };

        CsvExportUtil.export(100, fileName, map, querier);
    }

    private BigDecimal ratio(BigDecimal a, BigDecimal b) {
        if (Objects.isNull(b) || b.intValue() == 0) {
            return BigDecimal.ZERO;
        }
        return a.divide(b, 2, BigDecimal.ROUND_HALF_DOWN);
    }

}
